package workflow

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"strings"

	"shqsoft.cn/pas3ui/base"
)

//Context 配置上下文
type Context struct {
	XMLName   xml.Name   `xml:"WorkFlows"`
	WorkFlows []WorkFlow `xml:"WorkFlow"`
}

//GetWorkFlow 获取流程定义
func GetWorkFlow(id int) *WorkFlow {
	for _, wf := range wfContext.WorkFlows {
		if wf.ID == id {
			return &wf
		}
	}
	return nil
}

//WorkFlow WorkFlow参数
type WorkFlow struct {
	ID             int      `xml:"id,attr"`
	Name           string   `xml:"name,attr"`
	Actions        []Action `xml:"Action"`
	Entity         string   `xml:"entity,attr"`
	Recorder       string   `xml:"recorder,attr"`
	Manager        string   `xml:"manager,attr"`
	PermID         int      `xml:"permID,attr"`
	GetWfidFunc    string   `xml:"getWfidFunc,attr"`
	CreateCallBack string   `xml:"createCallBack,attr"`
	FinishCallBack string   `xml:"finishCallBack,attr"`
}

//Action Action
type Action struct {
	Step                 int       `xml:"step,attr"`
	Desc                 string    `xml:"desc,attr"`
	Executor             string    `xml:"executor,attr"`
	Appointer            string    `xml:"appointer,attr"`
	OrganFrom            string    `xml:"organFrom,attr"`
	IsAuto               bool      `xml:"isAuto,attr"`
	ConSign              bool      `xml:"conSign,attr"`
	CanBack              bool      `xml:"canBack,attr"`
	Recall               bool      `xml:"recall,attr"`
	End                  bool      `xml:"end,attr"`
	MustDesc             bool      `xml:"mustDesc,attr"`
	Excludes             []Exclude `xml:"Exclude"`
	CanManager           bool      `xml:"canManager,attr"`
	BeforeSubmitCallBack string    `xml:"beforeSubmitCallBack,attr"`
}

type Exclude struct {
	ID   string `xml:"id,attr"`
	Func string `xml:"func,attr"`
}

//GetAction 根据step获取Action
func (wf *WorkFlow) GetAction(step int) *Action {
	for _, act := range wf.Actions {
		if act.Step == step {
			return &act
		}
	}
	return nil
}

func (wf *WorkFlow) IsManager(userId int) (isMg bool) {
	if wf.Manager != "" {
		mArr := strings.Split(wf.Manager, ",")
		sql := `select COUNT(*) from "t_UserRole" WHERE "UserId"=? AND "RoleId" IN (?)`
		row := base.MYDB.Raw(sql, userId, mArr).Row()
		var count int
		row.Scan(&count)
		if count > 0 {
			isMg = true
		}
	}
	return
}

//WFContext 工作流配置信息
var wfContext Context

func init() {
	var err error
	var workPath string
	if workPath, err = base.WorkPath(); err != nil {
		base.Logger.Panic(fmt.Sprintf("获取执行路径出错%s", err.Error()))
		return
	}
	filePath := workPath + "/config/workflow.xml"
	if xmlBytes, err := ioutil.ReadFile(filePath); err == nil {
		if err := xml.Unmarshal(xmlBytes, &wfContext); err != nil {
			base.Logger.Panic(fmt.Sprintf("加载WorkFlow配置文件失败%s", err))
		}
	}
	initExtent()
	for _, wf := range wfContext.WorkFlows {
		if wf.CreateCallBack != "" {
			cb, ok := callBackFuncMap[wf.CreateCallBack]
			if !ok {
				base.Logger.Panic(fmt.Sprintf("流程%s定义的createCallBack:%s在callBackFuncMap中不存在", wf.Name, wf.CreateCallBack))
			}
			SetCreateCallBack(wf.ID, cb)
		}
		if wf.FinishCallBack != "" {
			cb, ok := callBackFuncMap[wf.FinishCallBack]
			if !ok {
				base.Logger.Panic(fmt.Sprintf("流程%s定义的finishCallBack:%s在callBackFuncMap中不存在", wf.Name, wf.FinishCallBack))
			}
			SetFinishCallBack(wf.ID, cb)
		}
		alen := len(wf.Actions)
		for i := 0; i < alen; i++ {
			act := wf.Actions[i]
			if act.Step != i+1 {
				base.Logger.Panic(fmt.Sprintf("流程%s配置错误，每个活动的step必须从1开始，并且连续", wf.Name))
				break
			}
			if act.BeforeSubmitCallBack != "" {
				cb, ok := callBackFuncMap[act.BeforeSubmitCallBack]
				if !ok {
					base.Logger.Panic(fmt.Sprintf("流程%s节点%s定义的BeforeSubmitCallBack:%s在callBackFuncMap中不存在", wf.Name, act.Desc, wf.FinishCallBack))
				}
				SetBeforeSubmitCallBack(wf.ID, act.Step, cb)
			}
			if i == alen-1 {
				wf.Actions[i].End = true
			}
		}
	}
}
